package cn.bonoon.kernel.bytecode.asm;

import java.lang.reflect.Constructor;
import java.util.Date;

import org.springframework.asm.Label;
import org.springframework.asm.MethodVisitor;
import org.springframework.asm.Opcodes;
import org.springframework.asm.Type;

import cn.bonoon.kernel.annotations.ObjectClass;
import cn.bonoon.kernel.util.StringHelper;

interface PropertyParser extends Opcodes{
	void parse(ASMAbstractProperty property, ASMEvent event) throws Exception;
}

abstract class AbstractPropertyParser implements PropertyParser{
	AbstractPropertyParser next;
	AbstractPropertyParser next(AbstractPropertyParser next){
		next.next = this;
		return next;
	}
	public void parse(ASMAbstractProperty property, ASMEvent event) throws Exception{
		if(!internalParse(property, property.setterType, event) && null != next){
			next.parse(property, event);
		}
	}
	void $else_end(ASMAbstractProperty property, ASMEvent event, Label ifnull) {
		if(property.ignoreNull){
			event.writer.visitLabel(ifnull);
		}else{
			Label ifelse = new Label();
			event.writer.visitJumpInsn(GOTO, ifelse);
			event.writer.visitLabel(ifnull);
			property.loadSetter(event);
			event.writer.visitInsn(ACONST_NULL);
			property.visitSetter(event.writer);
			event.writer.visitLabel(ifelse);
		}
	}
	abstract boolean internalParse(ASMAbstractProperty property, Class<?> propertyType, ASMEvent event) throws Exception;
}

//--------------------以下可读写数据库实体的操作类
/**
* 读跟写同样有效的功能
*/
class SameParser implements PropertyParser{

	@Override
	public void parse(ASMAbstractProperty property, ASMEvent event) throws Exception{
		if(!property.getterType.isPrimitive() && property.ignoreNull){
			Label ifnull = new Label();
			property.loadGetter(event);
			property.visitGetter(event.writer);
			event.writer.visitJumpInsn(IFNULL, ifnull);
			$parse(property, event);
			event.writer.visitLabel(ifnull);
		}else{
			$parse(property, event);
		}
	}

	private void $parse(ASMAbstractProperty property, ASMEvent event) {
		property.loadSetter(event);
		property.loadGetter(event);
		property.visitGetter(event.writer);
		property.visitSetter(event.writer);
	}
	
}

/**
* <pre>
* 读跟写同样有效的功能
* 把其它类型转为枚举类型（这里指的是非相同类型之间的转换），一般允许的情况如下：
* 1.把字符串类型转为枚举，使用枚举定义的名字，如果名字定义不正确，则转换异常
* 2.使用下标
* 
* 一般情况下，只允许把字符串和long或Long类型的数据转为日期类型
* </pre>
* @author jackson
*
*/
class ObjectParser extends AbstractPropertyParser{

	@Override
	boolean internalParse(ASMAbstractProperty property, Class<?> propertyType, ASMEvent event) throws Exception {
		Class<?> to = property.getterType;
		MethodVisitor visitor = event.writer;
		if(propertyType.isEnum()){
			if(int.class.equals(to)){
				ASMMethod values = new ASMMethod(propertyType, "values");
				property.loadSetter(event);
				values.visitMethodInsn(visitor, INVOKESTATIC, false);
				property.loadGetter(event);
				property.visitGetter(visitor);
				visitor.visitInsn(AALOAD);
				property.visitSetter(visitor);
			}else if(String.class.equals(to)){
				Label ifnull = new Label();
				property.loadGetter(event);
				property.visitGetter(visitor);
				visitor.visitJumpInsn(IFNULL, ifnull);
				ASMMethod valueOf = new ASMMethod(propertyType, "valueOf", String.class);
				property.loadSetter(event);
				property.loadGetter(event);
				property.visitGetter(visitor);
				valueOf.visitMethodInsn(visitor, INVOKESTATIC, false);
				property.visitSetter(visitor);
				$else_end(property, event, ifnull);
			}else if(Number.class.isAssignableFrom(to)){
				Label ifnull = new Label();
				property.loadGetter(event);
				property.visitGetter(visitor);
				visitor.visitJumpInsn(IFNULL, ifnull);
				ASMMethod values = new ASMMethod(propertyType, "values");
				property.loadSetter(event);
				values.visitMethodInsn(visitor, INVOKESTATIC, false);
				property.loadGetter(event);
				property.visitGetter(visitor);
				visitor.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(to), "intValue", "()I");
				visitor.visitInsn(AALOAD);
				property.visitSetter(visitor);
				$else_end(property, event, ifnull);
			}
			//只要是枚举类型的，不管是否能解析，都不应该交给下面的解析器了
			return true;
		}
		if(Date.class.equals(propertyType)){
			if(String.class.equals(to)){
				//格式化处理，都格式化成日期+时间类型，存和取的时候再根据具体的情况来处理
				ASMMethod toDatetime = new ASMMethod(StringHelper.class, "toDatetime", String.class);
				if(property.ignoreNull){
					int dateIndex = event.assignPoint();
					property.loadGetter(event);
					property.visitGetter(visitor);
					toDatetime.visitMethodInsn(visitor, INVOKESTATIC, false);
					visitor.visitVarInsn(ASTORE, dateIndex);
					visitor.visitVarInsn(ALOAD, dateIndex);
					Label ifnull = new Label();
					visitor.visitJumpInsn(IFNULL, ifnull);
					property.loadSetter(event);
					visitor.visitVarInsn(ALOAD, dateIndex);
					property.visitSetter(visitor);
					visitor.visitLabel(ifnull);
				}else{
					property.loadSetter(event);
					property.loadGetter(event);
					property.visitGetter(visitor);
					toDatetime.visitMethodInsn(visitor, INVOKESTATIC, false);
					property.visitSetter(visitor);
				}
			}else if(long.class.equals(to)){
				property.loadSetter(event);
				visitor.visitTypeInsn(NEW, "java/util/Date");  
				visitor.visitInsn(DUP);
				property.loadGetter(event);
				property.visitGetter(visitor);
				visitor.visitMethodInsn(INVOKESPECIAL, "java/util/Date", "<init>", "(J)V");
				property.visitSetter(visitor);
			}else if(Number.class.isAssignableFrom(to)){
				Label ifnull = new Label();
				property.loadGetter(event);
				property.visitGetter(visitor);
				visitor.visitJumpInsn(IFNULL, ifnull);
				property.loadSetter(event);
				visitor.visitTypeInsn(NEW, "java/util/Date");  
				visitor.visitInsn(DUP);
				property.loadGetter(event);
				property.visitGetter(visitor);
				visitor.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(to), "longValue", "()J");
				visitor.visitMethodInsn(INVOKESPECIAL, "java/util/Date", "<init>", "(J)V");
				property.visitSetter(visitor);
				$else_end(property, event, ifnull);
			}
			return true;
		}
		ObjectClass oc = property.objectProperty.getAnnotation(ObjectClass.class);
		Class<?> tryClass = null == oc ? propertyType : oc.value();
		try{
			Constructor<?> con = tryClass.getConstructor(to);
			String tcDes = Type.getInternalName(tryClass);
			property.loadSetter(event);
			visitor.visitTypeInsn(NEW, tcDes);  
			visitor.visitInsn(DUP);
			property.loadGetter(event);
			property.visitGetter(visitor);
			visitor.visitMethodInsn(INVOKESPECIAL, tcDes, "<init>", Type.getConstructorDescriptor(con));
			property.visitSetter(visitor);
			return true;
		}catch(Throwable t){
			return false;
		}
	}
}

/**
* <pre>
* 读跟写同样有效的功能
* 负责把其它类型的数据转成基本类型的数据
* 
* </pre>
* @author jackson
*
*/
class PrimitiveParser extends AbstractPropertyParser{
	/**
	 * <pre>
	 * 可以直接通过int类型转换过去的类型有：
	 * ->char/Character
	 * ->byte/Byte
	 * ->short/Short
	 * ->int/Integer
	 * </pre>
	 * 
	 */
	@Override
	boolean internalParse(ASMAbstractProperty property, Class<?> propertyType, ASMEvent event) throws Exception{
		Class<?> to = property.getterType;
		MethodVisitor visitor = event.writer;
		if(Integer.class.equals(propertyType)){//1 特殊对象：枚举类型
			if(to.isPrimitive()){
				$start(property, event);
				$primitive_int(visitor, to);
				visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
				$end_start(property, event);
			}else if(to.isEnum()){
				Label ifnull = $if(property, event);
				visitor.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(to), "ordinal", "()I");
				visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
				$end_if(property, event, ifnull);
			}else{
				Label ifnull = $if(property, event);
				$other_primitive(visitor, to, Integer.class, "intValue", ICONST_0, ICONST_1);
				visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
				$end_if(property, event, ifnull);
			}
		}else if(Long.class.equals(propertyType)){//2 特殊对象：日期类型
			if(to.isPrimitive()){
				$start(property, event);
				if(!long.class.equals(to)) $primitive_long(visitor, to); 
				visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
				$end_start(property, event);
			}else if(Date.class.equals(to)){
				Label ifnull = $if(property, event);
				visitor.visitMethodInsn(INVOKEVIRTUAL, "java/util/Date", "getTime", "()J");
				visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
				$end_if(property, event, ifnull);
			}else{
				Label ifnull = $if(property, event);
				$other_primitive(visitor, to, Long.class, "longValue", ICONST_0, ICONST_1);
				visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
				$end_if(property, event, ifnull);
			}
		}else if(Double.class.equals(propertyType)){//3
			if(to.isPrimitive()){
				$start(property, event);
				if(!double.class.equals(to)) $primitive_double(visitor, to); 
				visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(J)Ljava/lang/Double;");
				$end_start(property, event);
			}else{
				Label ifnull = $if(property, event);
				$other_primitive(visitor, to, Double.class, "doubleValue", ICONST_0, ICONST_1);
				visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(J)Ljava/lang/Double;");
				$end_if(property, event, ifnull);
			}
		}else if(Float.class.equals(propertyType)){//4
			if(to.isPrimitive()){
				$start(property, event);
				if(!float.class.equals(to)) $primitive_float(visitor, to);
				visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(J)Ljava/lang/Float;");
				$end_start(property, event);
			}else{
				Label ifnull = $if(property, event);
				$other_primitive(visitor, to, Float.class, "floatValue", ICONST_0, ICONST_1);
				visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(J)Ljava/lang/Float;");
				$end_if(property, event, ifnull);
			}
		}else if(Boolean.class.equals(propertyType)){//5
			if(to.isPrimitive()){
				$start(property, event);
				if(!boolean.class.equals(to)){
					$primitive_boolean(property, event, to);
				}
				visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
				$end_start(property, event);
			} else {
				Label ifnull = $if(property, event);
				if(!$other_boolean(property, event, to)){
					//直接调用对象的toString方法来解析boolean值
					visitor.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(to), "toString", "()Ljava/lang/String;");
					visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Ljava/lang/String;)Ljava/lang/Boolean;");
				}
				$end_if(property, event, ifnull);
			}
		}else if(propertyType.isPrimitive()){
			if(boolean.class.equals(propertyType)){
				if(to.isPrimitive()){
					$start(property, event);
					$primitive_boolean(property, event, to);
					$end_start(property, event);
				} else {
					Label ifnull = $if(property, event);
					if(Boolean.class.equals(to)){
						visitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
					}else if(!$other_boolean(property, event, to)){
						//直接调用对象的toString方法来解析boolean值
						visitor.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(to), "toString", "()Ljava/lang/String;");
						visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Ljava/lang/String;)Ljava/lang/Boolean;");
						visitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
					}
					property.visitSetter(visitor);
					if(property.ignoreNull){
						visitor.visitLabel(ifnull);
					}else{
						Label ifelse = new Label();
						visitor.visitJumpInsn(GOTO, ifelse);
						visitor.visitLabel(ifnull);
						property.loadSetter(event);
						visitor.visitLdcInsn(false);
						property.visitSetter(visitor);
						visitor.visitLabel(ifelse);
					}
				} 
			}else if(long.class.equals(propertyType)){
				if(to.isPrimitive()){
					$start(property, event);
					$primitive_long(visitor, to);
					$end_start(property, event);
				}else{ 
					Label ifnull = $if(property, event);
					if(Date.class.equals(to)){
						visitor.visitMethodInsn(INVOKEVIRTUAL, "java/util/Date", "getTime", "()J");
					}else if(Character.class.equals(to)){
						visitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
						visitor.visitInsn(I2L);
					}else{
						$other_primitive(visitor, to, Long.class, "longValue", LCONST_0, LCONST_1);
					}
					property.visitSetter(visitor);
					if(property.ignoreNull){
						visitor.visitLabel(ifnull);
					}else{
						Label ifelse = new Label();
						visitor.visitJumpInsn(GOTO, ifelse);
						visitor.visitLabel(ifnull);
						property.loadSetter(event);
						visitor.visitInsn(LCONST_0);
						property.visitSetter(visitor);
						visitor.visitLabel(ifelse);
					}
				}
			}else if(double.class.equals(propertyType)){
				if(to.isPrimitive()){
					$start(property, event);
					$primitive_double(visitor, to);
					$end_start(property, event);
				}else{ 
					Label ifnull = $if(property, event);
					if(Character.class.equals(to)){
						visitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
						visitor.visitInsn(I2D);
					}else{
						$other_primitive(visitor, to, Double.class, "doubleValue", DCONST_0, DCONST_1);
					}
					property.visitSetter(visitor);
					if(property.ignoreNull){
						visitor.visitLabel(ifnull);
					}else{
						Label ifelse = new Label();
						visitor.visitJumpInsn(GOTO, ifelse);
						visitor.visitLabel(ifnull);
						property.loadSetter(event);
						visitor.visitInsn(DCONST_0);
						property.visitSetter(visitor);
						visitor.visitLabel(ifelse);
					}
				}
			}else if(float.class.equals(propertyType)){
				if(to.isPrimitive()){
					$start(property, event);
					$primitive_float(visitor, to);
					$end_start(property, event);
				}else{ 
					Label ifnull = $if(property, event);
					if(Character.class.equals(to)){
						visitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
						visitor.visitInsn(I2F);
					}else{
						$other_primitive(visitor, to, Float.class, "floatValue", FCONST_0, FCONST_1);
					}
					property.visitSetter(visitor);
					if(property.ignoreNull){
						visitor.visitLabel(ifnull);
					}else{
						Label ifelse = new Label();
						visitor.visitJumpInsn(GOTO, ifelse);
						visitor.visitLabel(ifnull);
						property.loadSetter(event);
						visitor.visitInsn(FCONST_0);
						property.visitSetter(visitor);
						visitor.visitLabel(ifelse);
					}
				}
			}else{
				if(to.isPrimitive()){
					$start(property, event);
					$primitive_int(visitor, to);
					$end_start(property, event);
				}else{ 
					Label ifnull = $if(property, event);
					if(to.isEnum()){
						/*
						 * 这里可以把枚举类型转为：
						 * ->int
						 * ->short
						 * ->byte
						 * ->char
						 * 这几种类型，但一般只建议转成int类型；因为从枚举转为基本类型只支持int，其它格式是无法相互转换的
						 * 定义成其他三种类型时是能转值的，应该是在特殊的场合下才使用
						 */
						visitor.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(to), "ordinal", "()I");
					}else if(Character.class.equals(to)){
						visitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
					}else{
						$other_primitive(visitor, to, Integer.class, "intValue", ICONST_0, ICONST_1);
					}
					property.visitSetter(visitor);
					if(property.ignoreNull){
						visitor.visitLabel(ifnull);
					}else{
						Label ifelse = new Label();
						visitor.visitJumpInsn(GOTO, ifelse);
						visitor.visitLabel(ifnull);
						property.loadSetter(event);
						visitor.visitInsn(ICONST_0);
						property.visitSetter(visitor);
						visitor.visitLabel(ifelse);
					}
				}
			}
		}else if(Character.class.equals(propertyType)){//6 
			if(to.isPrimitive()){
				$start(property, event);
				if(!char.class.equals(to)){
					$primitive_int(visitor, to);
					visitor.visitInsn(I2C);
				}
				visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
				$end_start(property, event);
			}else{
				Label ifnull = $if(property, event);
				$other_primitive(visitor, to, Integer.class, "intValue", ICONST_0, ICONST_1);
				visitor.visitInsn(I2C);
				visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
				$end_if(property, event, ifnull);
			}
		}else if(Short.class.equals(propertyType)){//7
			if(to.isPrimitive()){
				$start(property, event);
				if(!short.class.equals(to)){
					$primitive_int(visitor, to);
					visitor.visitInsn(I2S);
				}
				visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
				$end_start(property, event);
			}else{
				Label ifnull = $if(property, event);
				$other_primitive(visitor, to, Integer.class, "intValue", ICONST_0, ICONST_1);
				visitor.visitInsn(I2S);
				visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
				$end_if(property, event, ifnull);
			}
		}else if(Byte.class.equals(propertyType)){//8
			if(to.isPrimitive()){
				$start(property, event);
				if(!short.class.equals(to)){
					$primitive_int(visitor, to);
					visitor.visitInsn(I2B);
				}
				visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
				$end_start(property, event);
			}else{
				Label ifnull = $if(property, event);
				$other_primitive(visitor, to, Integer.class, "intValue", ICONST_0, ICONST_1);
				visitor.visitInsn(I2B);
				visitor.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
				$end_if(property, event, ifnull);
			}
		}else{
			return false;
		}
		return true;
	}
	
	void $primitive_boolean(ASMAbstractProperty property, ASMEvent event, Class<?> to){
		MethodVisitor visitor = event.writer;
		if(long.class.equals(to)){
			visitor.visitInsn(LCONST_1);
			visitor.visitInsn(LCMP);
			$boolean_primitive(visitor, IFNE, ICONST_0, ICONST_1);
		}else if(char.class.equals(to)){
			/*
			 * 字符表示"true"值的有三种情况：'1'、'T'和't'
			 */
			Label ifeq = new Label();
			Label ifelse = new Label();
			visitor.visitIntInsn(BIPUSH, 49);
			visitor.visitJumpInsn(IF_ICMPEQ, ifeq);
			property.loadGetter(event);
			property.visitGetter(visitor);
			visitor.visitIntInsn(BIPUSH, 84);
			visitor.visitJumpInsn(IF_ICMPEQ, ifeq);
			property.loadGetter(event);
			property.visitGetter(visitor);
			visitor.visitIntInsn(BIPUSH, 116);
			visitor.visitJumpInsn(IF_ICMPEQ, ifeq);
			visitor.visitInsn(ICONST_0);
			visitor.visitJumpInsn(GOTO, ifelse);
			visitor.visitLabel(ifeq);
			visitor.visitInsn(ICONST_1);
			visitor.visitLabel(ifelse);
		}else if(float.class.equals(to)){
			visitor.visitInsn(FCONST_1);
			visitor.visitInsn(FCMPL);
			$boolean_primitive(visitor, IFNE, ICONST_0, ICONST_1);
		}else if(double.class.equals(to)){
			visitor.visitInsn(DCONST_1);
			visitor.visitInsn(DCMPL);
			$boolean_primitive(visitor, IFNE, ICONST_0, ICONST_1);
		}else{
			visitor.visitInsn(ICONST_1);
			$boolean_primitive(visitor, IF_ICMPNE, ICONST_0, ICONST_1);
		}
	}
	
	boolean $other_boolean(ASMAbstractProperty property, ASMEvent event, Class<?> to){
		MethodVisitor visitor = event.writer;
		if(Number.class.isAssignableFrom(to)){
			visitor.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(to), "intValue", "()I");
			visitor.visitInsn(ICONST_1);
			$boolean_primitive(visitor, IF_ICMPNE, ICONST_0, ICONST_1);
		}else if(Character.class.equals(to)){
			Label ifeq = new Label();
			Label ifelse = new Label();
			visitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
			visitor.visitIntInsn(BIPUSH, 49);
			visitor.visitJumpInsn(IF_ICMPEQ, ifeq);
			property.loadGetter(event);
			property.visitGetter(visitor);
			visitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
			visitor.visitIntInsn(BIPUSH, 84);
			visitor.visitJumpInsn(IF_ICMPEQ, ifeq);
			property.loadGetter(event);
			property.visitGetter(visitor);
			visitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
			visitor.visitIntInsn(BIPUSH, 116);
			visitor.visitJumpInsn(IF_ICMPEQ, ifeq);
			visitor.visitInsn(ICONST_0);
			visitor.visitJumpInsn(GOTO, ifelse);
			visitor.visitLabel(ifeq);
			visitor.visitInsn(ICONST_1);
			visitor.visitLabel(ifelse);
		}else{
			return false;
		}
		return true;
	}
	
	void $primitive_float(MethodVisitor visitor, Class<?> to) {
		if(boolean.class.equals(to)){
			$boolean_primitive(visitor, IFEQ, FCONST_0, FCONST_1);
		}else if(long.class.equals(to)){
			visitor.visitInsn(L2F);
		}else if(double.class.equals(to)){
			visitor.visitInsn(D2F);
		}else{
			visitor.visitInsn(I2F);
		}
	}
	
	void $primitive_double(MethodVisitor visitor, Class<?> to) {
		if(boolean.class.equals(to)){
			$boolean_primitive(visitor, IFEQ, DCONST_0, DCONST_1);
		}else if(long.class.equals(to)){
			visitor.visitInsn(L2D);
		}else if(float.class.equals(to)){
			visitor.visitInsn(F2D);
		}else{
			visitor.visitInsn(I2D);
		}
	}
	
	void $primitive_long(MethodVisitor visitor, Class<?> to) {
		if(boolean.class.equals(to)){
			$boolean_primitive(visitor, IFEQ, LCONST_0, LCONST_1);
		}else if(double.class.equals(to)){
			visitor.visitInsn(D2L);
		}else if(float.class.equals(to)){
			visitor.visitInsn(F2L);
		}else{
			visitor.visitInsn(I2L);
		}
	}
	
	void $primitive_int(MethodVisitor visitor, Class<?> to){
		if(boolean.class.equals(to)){
			$boolean_primitive(visitor, IFEQ, ICONST_0, ICONST_1);
		}else if(long.class.equals(to)){
			visitor.visitInsn(L2I);
		}else if(double.class.equals(to)){
			visitor.visitInsn(D2I);
		}else if(float.class.equals(to)){
			visitor.visitInsn(F2I);
		}
	}
	
	void $other_primitive(MethodVisitor visitor, Class<?> to, Class<?> numClass, String name, int const_0, int const_1) throws Exception {
		if(Number.class.isAssignableFrom(to)){
			String des = Type.getMethodDescriptor(to.getDeclaredMethod(name));
			visitor.visitMethodInsn(INVOKEVIRTUAL, Type.getInternalName(to), name, des);
		}else if(Boolean.class.equals(to)){
			visitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
			$boolean_primitive(visitor, IFEQ, const_0, const_1);
		}else{
			String classPath = Type.getInternalName(numClass);
			String valdes = Type.getMethodDescriptor(numClass.getDeclaredMethod(name));
			String ofdes = Type.getMethodDescriptor(numClass.getDeclaredMethod("valueOf", String.class));
			visitor.visitMethodInsn(INVOKESTATIC, classPath, "valueOf", ofdes);
			visitor.visitMethodInsn(INVOKEVIRTUAL, classPath, name, valdes);
		}
	}
	
	void $boolean_primitive(MethodVisitor visitor, int jump_if, int const_0, int const_1){
		Label ifeq = new Label();
		Label ifelse = new Label();
		visitor.visitJumpInsn(jump_if, ifeq);
		visitor.visitInsn(const_1);
		visitor.visitJumpInsn(GOTO, ifelse);
		visitor.visitLabel(ifeq);
		visitor.visitInsn(const_0);
		visitor.visitLabel(ifelse);
	}
	
	void $start(ASMAbstractProperty property, ASMEvent event){
		property.loadSetter(event);
		property.loadGetter(event);
		property.visitGetter(event.writer);
	}
	
	void $end_start(ASMAbstractProperty property, ASMEvent event){
		property.visitSetter(event.writer);
	}
	
	Label $if(ASMAbstractProperty property, ASMEvent event){
		Label ifnull = new Label();
		property.loadGetter(event);
		property.visitGetter(event.writer);
		event.writer.visitJumpInsn(IFNULL, ifnull);
		$start(property, event);
		return ifnull;
	}
	
	void $end_if(ASMAbstractProperty property, ASMEvent event, Label ifnull){
		$end_start(property, event);
		$else_end(property, event, ifnull);
	}
}